package com.hmall.search.service.impl;

import cn.hutool.core.util.StrUtil;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.json.JsonData;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hmall.common.domain.PageDTO;
import com.hmall.item.domain.po.Item;
import com.hmall.search.config.EsConfiguration;
import com.hmall.search.domain.po.ItemDoc;
import com.hmall.search.domain.query.ItemPageQuery;
import com.hmall.search.properties.EsProperties;
import com.hmall.search.service.ISearchService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.test.web.servlet.RequestBuilder;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Slf4j
@Service
public class SearchServiceImpl implements ISearchService {
    @Autowired
    private EsConfiguration esConfiguration;
    @Autowired
    private EsProperties esProperties;

    @Override
    public PageDTO<ItemDoc> searchItems(ItemPageQuery query) {
        SearchRequest.Builder builder = new SearchRequest.Builder().index("items");
        //bool查询
        builder.query(q->q
                .bool(b->{
                    if (StrUtil.isNotBlank(query.getKey())) {
                        b.must(m -> m
                                .match(mm -> mm
                                        .field("name").query(query.getKey())));
                    } else {
                        q.matchAll(m -> m); // 查询所有
                    }
                    if(StrUtil.isNotBlank(query.getCategory())){
                        b.filter(f->f
                                .term(t->t
                                        .field("category").value(query.getCategory())));
                    }
                    if(StrUtil.isNotBlank(query.getBrand())){
                        b.filter(f->f
                                .term(t->t
                                        .field("brand").value(query.getBrand())));
                    }
                    if (query.getMinPrice() != null || query.getMaxPrice() != null) {
                        b.filter(f -> f.range(r -> {
                            r.field("price");
                            if (query.getMinPrice() != null) r.gte(JsonData.of(query.getMinPrice()));
                            if (query.getMaxPrice() != null) r.lte(JsonData.of(query.getMaxPrice()));
                            return r;
                        }));
                    }
                    return b;
                }));
        builder.from((query.getPageNo()-1)*query.getPageSize()).size(query.getPageSize());
        if(query.getSortBy()!=null&&!query.getSortBy().isEmpty()){
            SortOrder order = query.getIsAsc() ? SortOrder.Asc : SortOrder.Desc;
            builder.sort(s -> s
                    .field(f -> f
                            .field(query.getSortBy())
                            .order(order)));
        }
        builder.highlight(h->h
                .fields("name",f->f
                        .preTags("<em>")
                        .postTags("</em>")));

        SearchResponse<ItemDoc> response = null;
        SearchRequest build = builder.build();
        try {
            response = esConfiguration.esClient(esProperties).search(build, ItemDoc.class);
        } catch (IOException e) {
            log.error("ES 搜索失败", e);
            throw new RuntimeException("搜索失败，请稍后重试");
        }
        List<Hit<ItemDoc>> hits = response.hits().hits();
        List<ItemDoc> itemDocs = new ArrayList<>();
        hits.forEach(hit-> {
            if(hit.source()!=null) {
                ItemDoc source = hit.source();
                Map<String, List<String>> highlight = hit.highlight();
                List<String> keyList = highlight.get("name");
                if(keyList!=null){
                    source.setName(keyList.get(0));
                }
                itemDocs.add(source);
            }
        });
        Page<ItemDoc> page = new Page<>();
        PageDTO<ItemDoc> itemDocPage = new PageDTO<>();
        long total = response.hits().total().value();
        long pages = (total + query.getPageSize() - 1) / query.getPageSize();
        itemDocPage.setList(itemDocs);
        itemDocPage.setTotal(total);
        itemDocPage.setTotalPage(pages);
        return itemDocPage;
    }
}
